using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Microsoft.Win32;
using Studio.Foundation.ImageBox;

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Drawing;
using Studio.Windows;

namespace Studio.Game.GameBox
{
    /// <summary>
    /// Agent to enable the fundemental Game Controlling
    /// </summary>
    public class GameAgent : IGameAgent
    {

        #region Properties: IsSpying, WindowSpy, Handle, AgentMode

        public string GameName = "Abstract Agent";

        private bool _IsSpying;
        /// <summary>
        /// Indicate if the mouse is captured 
        /// </summary>
        public bool IsSpying
        {
            get { return _IsSpying; }
        }

        private WindowSpy _WindowSpy;
        /// <summary>
        /// Window Finder
        /// </summary>
        public WindowSpy WindowSpy
        {
            get { return _WindowSpy; }
        }

        protected AgentModes _AgentMode = AgentModes.NOMARL;
        /// <summary>
        /// Agent mode: strategies.
        /// </summary>
        public AgentModes AgentMode
        {
            get { return _AgentMode; }
            set { _AgentMode = value; }
        }

        private AgentStatus _GameStatus = AgentStatus.NONE; // Do not allow inherited class access directly.
        /// <summary>
        /// Game status : Pause or Run or ....
        /// </summary>
        public AgentStatus GameStatus
        {
            get { return _GameStatus; }
            set { _GameStatus = value; }
        }

        protected IntPtr _Handle;
        /// <summary>
        /// Handle of the game embeded window to be hacked.
        /// </summary>
        public IntPtr Handle
        {
            get { return _Handle; }
        }

        /// <summary>
        /// public constructor
        /// </summary>
        public GameAgent(string GameName)
        {
            _WindowSpy = new WindowSpy();
            _Linguist = new AgentScriptParser();
            _IsSpying = false;

            // Set Game Controller
            _GameBoss.Enabled = false;
            _GameBoss.Interval = 500;
            _GameBoss.Tick += new EventHandler(_GameBoss_Tick);

            // Load Patterns
            this.GameName = GameName;
        }

        #endregion

        #region Window Recognization

        public void BeginFindGame(Form Caller)
        {
            _IsSpying = true;
            WinAPI.SetCapture(Caller.Handle);
            // Attention: this is not WinAPI
            // Cursor cursor = WindowSpy.LoadCursorFromFile("Resources\\Gear3D.cur");
            // Caller.Cursor = (null == cursor) ? new Cursor(Caller.GetType(), "Resources.Gear3D.cur") : cursor;
        }

        public void EndFindGame(Form Caller)
        {
            // If spying a window
            if (true == _IsSpying)
            {
                _IsSpying = false;
                WinAPI.ReleaseCapture();
                Caller.Cursor = Cursors.Default;
            }
            // Earse last window frame if necessary
            _WindowSpy.EarseLastWindow();
            // Set game window handle
            _Handle = _WindowSpy.Handle;
        }

        /// <summary>
        /// Return ture if the right game found.
        /// </summary>
        private bool AnalyseGame(string GameTitle, bool CompleteMatch)
        {
            if (true == CompleteMatch)
                return _WindowSpy.WindowText == GameTitle;
            else
                return _WindowSpy.WindowText.Contains(GameTitle);
        }

        public bool FindGameWindow(string GameTitle, bool CompleteMatch)
        {
            // Get window informations under the cursor
            _WindowSpy.GetWindowInformationFromCursor();
            // The right window found ?
            return AnalyseGame(GameTitle, CompleteMatch);
        }

        public Point GameLocation
        {
            get 
            {
                return GameBox.WindowSpy.GetWindowLocation(_Handle);
            }
        }

        /// <summary>
        /// Make game foreground.
        /// </summary>
        public bool ActivateGame()
        {
            // Assert Handle
            if (IntPtr.Zero == _Handle) return false;
            IntPtr Hwnd = WinAPI.GetForegroundWindow();
            if (Hwnd != _Handle)
            {
                WinAPI.SetForegroundWindow(_Handle);
                return true;
            }
            // No need to set.
            return false;
        }

        #endregion

        #region Mouse & Keyboard simulation
        /// <summary>
        /// Attach this event to Game Window Handle
        /// </summary>
        public bool SendKeys(string Keys, bool SwitchBack)
        {
            // Invalid game window handle
            if (null == _Handle || IntPtr.Zero == _Handle)
                return false;

            IntPtr Handle = WinAPI.GetForegroundWindow();
            WinAPI.SetForegroundWindow(_Handle);
            // Send message directly to foreground window
            System.Windows.Forms.SendKeys.SendWait(Keys);

            // Set foregound window back if necessary
            if (true == SwitchBack)
                WinAPI.SetForegroundWindow(Handle);
            return true;
        }

        public bool SendWord(string Word, int PatchBackspace, bool SwitchBack)
        {
            // Patch backspaces
            string Backspace = string.Empty;
            for (int i = 0; i < PatchBackspace; i++) Backspace += "{BS}";
            // Send key simulation
            return SendKeys(Backspace + Word + "{ENTER}", SwitchBack);
        }

        #endregion

        #region IGameAgent Members, Common AgentScript Parser

        /// <summary>
        /// The Parser
        /// </summary>
        protected AgentScriptParser _Linguist;

        protected int _GameSpeed = 0;
        /// <summary>
        /// Gamme automation speed
        /// </summary>
        public virtual int GameSpeed
        {
            get { return _GameSpeed; }
            set { _GameSpeed = value; }
        }

        public virtual void Run(AgentScript Scripts) { }

        public virtual string Run(AgentScriptSentence Sentence)
        {
            return _Linguist.Run(Sentence);
        }

        public virtual string Run(string Format, params object[] args)
        {
            return _Linguist.Run(new AgentScriptSentence(Format, args));
        }

        public virtual void Start()
        {
            _GameStatus = AgentStatus.ROUND;
            _GameBoss.Enabled = true;
        }


        public virtual void Pause()
        {
            _GameStatus = AgentStatus.PAUSE;
        }

        public virtual void Stop()
        {
            _GameStatus = AgentStatus.PAUSE;        // To be modified! by marstone, 20070727
        }

        public virtual void Restart()
        {
            Stop();
            Start();
        }

        public virtual void Step() { }


        #endregion

        #region Agent GameFlow Control

        protected System.Windows.Forms.Timer _GameBoss = new System.Windows.Forms.Timer();

        protected void _GameBoss_Tick(object sender, EventArgs e)
        {
            switch (_GameStatus)
            {
                case AgentStatus.NONE:
                    ((Timer)sender).Enabled = false;
                    MessageBox.Show("Game is not Ready.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    break;
                case AgentStatus.COMPLETE:
                    ((Timer)sender).Enabled = false;
                    MessageBox.Show("Game completed.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    break;
                case AgentStatus.ERROR:
                    ((Timer)sender).Enabled = false;
                    MessageBox.Show("Game error when running.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                case AgentStatus.PAUSE:
                    // Do nothing
                    break;
                case AgentStatus.READY:
                    // Do nothing
                    break;
                case AgentStatus.RUN:
                    // OnRunning();
                    break;
                case AgentStatus.ROUND:
                    // OnRound();
                    break;
            }
        }

        #endregion

        #region HotKey Register & Unregister


        /// <summary>
        /// Hot key ids. Used for RegisterHotkey
        /// </summary>
        public const int ID_HOTKEY_PAUSE = 100;
        public const int ID_HOTKEY_START = 101;
        public const int ID_HOTKEY_SHOW = 200;
        public const int ID_HOTKEY_HIDE = 202;
        public const int ID_HOTKEY_CAPTURE = 300;

        /// <summary>
        /// Call WinAPI Directly
        /// </summary>
        public static void RegisterHotKey(IntPtr Handle)
        {
            WinAPI.RegisterHotKey(Handle, ID_HOTKEY_HIDE, (uint)(KeyModifiers.Control | KeyModifiers.Alt), Keys.H);
            WinAPI.RegisterHotKey(Handle, ID_HOTKEY_SHOW, (uint)(KeyModifiers.Control | KeyModifiers.Alt), Keys.O);
            WinAPI.RegisterHotKey(Handle, ID_HOTKEY_START, (uint)(KeyModifiers.Control | KeyModifiers.Alt), Keys.S);
            WinAPI.RegisterHotKey(Handle, ID_HOTKEY_PAUSE, (uint)(KeyModifiers.Control | KeyModifiers.Alt), Keys.P);
            WinAPI.RegisterHotKey(Handle, ID_HOTKEY_CAPTURE, (uint)(KeyModifiers.Control | KeyModifiers.Alt), Keys.W);
        }

        public static void UnregisterHotKey(IntPtr Handle)
        {
            WinAPI.UnregisterHotKey(Handle, ID_HOTKEY_HIDE);
            WinAPI.UnregisterHotKey(Handle, ID_HOTKEY_SHOW);
            WinAPI.UnregisterHotKey(Handle, ID_HOTKEY_START);
            WinAPI.UnregisterHotKey(Handle, ID_HOTKEY_PAUSE);
            WinAPI.UnregisterHotKey(Handle, ID_HOTKEY_CAPTURE);
        }



        #endregion

    }
}
